const RENDER_TO_DOM = Symbol("render to dom");

function replaceContent(range,node){
  range.insertNode(node)
  range.setStartAfter(node)
  range.deleteContents();
  range.setStartBefore(node)
  range.setEndAfter(node)
}

class Component {
  constructor() {
    this.props = {};
    this.children = [];
    this._root = null;
    this._range = null;
    this.state = null;
  }
  
  setAttribute(key, value) {
    this.props[key] = value;
  }
  
  appendChild(component) {
    this.children.push(component);
  }
  
  get vdom() {
    return this.render().vdom;
  }
  
  // get vchildren() {
  //   return this.children.map(child => child.vdom);
  // }
  // 当数据变化重新渲染的时候，就不能append了，这个时候需要一个可以将组件渲染到指定位置的函数，
  // dom 中可以指定位置的 api 是 Range
  [RENDER_TO_DOM](range) {
    this._range = range;
    this._vdom = this.vdom;
    
    this._vdom[RENDER_TO_DOM](range);
  }
  
  // 重新绘制 由 更新替代
  // rerender() {
  //   this._range.deleteContents();
  //   this[RENDER_TO_DOM](this._range);
  // }
  update() {
    let isSameNode = (oldNode, newNode) => {
      if (oldNode.type !== newNode.type) {
        return false;
      }
      for (let name in newNode.props) {
        if (newNode.props[name] !== oldNode.props[name]) {
          return false;
        }
      }
      if (Object.keys(oldNode.props).length > Object.keys(newNode.props).length) {
        return false;
      }
      return !(newNode.type === "#text" && newNode.content !== oldNode.content);
      
    };
    let update = (oldNode, newNode) => {
      if (!isSameNode(oldNode, newNode)) {
        newNode[RENDER_TO_DOM](oldNode._range);
        return;
      }
      newNode._range = oldNode._range;
      
      
      let newChildren = newNode.vchildren;
      let oldChildren = oldNode.vchildren;
      if (!oldChildren || oldChildren.length < 1) {
        return;
      }
      let tailRange = oldChildren[oldChildren.length - 1]._range;
      
      for (let i = 0; i < newChildren.length/*||oldChildren.length*/; i++) {
        let newChild = newChildren[i];
        let oldChild = oldChildren[i];
        if (i < oldChildren.length) {
          update(oldChild, newChild);
        } else {
          let range = document.createRange();
          range.setStart(tailRange.endContainer, tailRange.endOffset);
          range.setEnd(tailRange.endContainer, tailRange.endOffset);
          newChild[RENDER_TO_DOM](range);
          tailRange = range;
        }
      }
    };
    let vdom = this.vdom;
    update(this._vdom, vdom);
    this._vdom = vdom;
  }
  
  setState(newState) {
    if (newState !== null && typeof newState === "object") {
      if (this.state === null) {
        this.state = newState;
      } else {
        let merge = (oldState, newState) => {
          for (let key in newState) {
            if (oldState[key] !== null && typeof oldState[key] === "object") {
              merge(oldState[key], newState[key]);
            } else {
              oldState[key] = newState[key];
            }
          }
        };
        merge(this.state, newState);
      }
      this.update();
    }
  }
  
  // get root() {
  //   if (!this._root) {
  //     // 自动形成一个递归调用
  //     this._root = this.render().root;
  //   }
  //   return this._root;
  // }
}

class ElementWrapper extends Component {
  constructor(type) {
    super();
    this.type = type;
  }
  
  get vdom() {
    this.vchildren = this.children.map((item) => item.vdom);
    return this;
  }
  
  /*
   * 基于虚拟 Dom 来创建真实的 Dom
   * */
  [RENDER_TO_DOM](range) {
    // 保存range ， 更新的时候使用
    this._range = range;
    let root = document.createElement(this.type);
    // range.deleteContents();
    
    for (let key in this.props) {
      let value = this.props[key];
      if (key.match(/^on([\s\S]+)$/)) {
        root.addEventListener(RegExp.$1.replace(/^[\s\S]+$/, c => c.toLowerCase()), value);
      } else if (key === "className") {
        root.setAttribute("class", value);
      } else {
        root.setAttribute(key, value);
      }
    }
    if (!this.vchildren) {
      this.vchildren = this.children.map((item) => item.vdom);
    }
    for (let component of this.vchildren) {
      let childRange = document.createRange();
      childRange.setStart(root, root.childNodes.length);
      childRange.setEnd(root, root.childNodes.length);
      component[RENDER_TO_DOM](childRange);
    }
    // range.insertNode(root);
    replaceContent(range, root)
  }
}

class TextWrapper extends Component {
  constructor(content) {
    super();
    this.type = "#text";
    this.content = content;
  }
  
  get vdom() {
    // this.vchildren = this.content;
    return this;
  }
  
  [RENDER_TO_DOM](range) {
    // 保存range ， 更新的时候使用
    this._range = range;
    const root = document.createTextNode(this.content);
    replaceContent(range, root)
  }
}


function createElement(type, attributes, ...children) {
  let e;
  if (typeof type === "string") {
    e = new ElementWrapper(type);
  } else {
    e = new type;
  }
  
  for (let p in attributes) {
    e.setAttribute(p, attributes[p]);
  }
  
  const insertChildren = (children) => {
    for (let child of children) {
      if (child === null || child === undefined || child === true || child === false) {
        continue;
      }
      if (typeof child === "string") {
        child = new TextWrapper(child);
      }
      if (Array.isArray(child)) {
        insertChildren(child);
      } else {
        e.appendChild(child);
      }
    }
  };
  insertChildren(children);
  return e;
}

const render = (component, parentElement) => {
  let range = document.createRange();
  range.setStart(parentElement, 0);
  // 这里使用 childNodes 将文本节点，注释节点，元素节点全部删掉
  range.setEnd(parentElement, parentElement.childNodes.length);
  range.deleteContents();
  component[RENDER_TO_DOM](range);
  // parentElement.appendChild(component.root);
};
export {
  createElement, Component, render,
};
